#ifndef PROCEDURE_H
#define PROCEDURE_H

#include <QObject>
#include <QtDebug>

#include "variable.h"

class Arg
{
private:
	VariableType m_Type;
	QString m_Id;

public:
	Arg(){}
	Arg(VariableType type, QString id) : m_Type(type), m_Id(id) {}
	~Arg(){} 

	VariableType type(){ return m_Type; } 
	QString id(){ return m_Id; }

	bool operator==(const Arg &a) const { return m_Id == a.m_Id; }
};

class Procedure
{
private:
	QString m_Id;				// id funkcji
	SyntaxTreeNode* m_Body;		// rozbite na atomy cialo funkcji (Block)
	
	VariableType m_RetType;		// zwracany typ
	QList<Arg> m_Args;			// typy argumentow

public:
	Procedure() : m_Body(NULL) {}	
	~Procedure() {}

	QString id(){ return m_Id; }
	void setID(QString id){ m_Id = id; }
	void setID( Symbol id)
	{
		m_Id = id.value();
	}

	SyntaxTreeNode* body(){ return m_Body; }
	void setBody(SyntaxTreeNode* body) { m_Body = body; }

	VariableType retType() { return m_RetType; }
	void setRetType(VariableType ret){ m_RetType = ret; }
	void setRetType(Symbol ret)
	{ 
		if(ret.value() == QObject::tr("fraction"))
		{
			m_RetType = FractionType;
		}
		else if(ret.value() == QObject::tr("bool"))
		{
			m_RetType = BooleanType;					 
		}
		else if(ret.value() == QObject::tr("void"))
		{
			m_RetType = VoidType;					 
		}
		else
			qDebug() << "ERR(Procedure setRetType() ) : Unknown type!";
	}

	QList<Arg> args() { return m_Args; }
	bool addArg(Arg a, bool forced = false)
	{
		if(m_Args.contains(a) && forced == false)
		{			
			return false;
		}
		m_Args.append(a);
		return true;
	}

	bool addArg(Symbol t, Symbol id)
	{
		if(t.value() == QObject::tr("fraction"))
		{
			Arg a(FractionType, id.value());
			return addArg(a);
		}
		else if(t.value() == QObject::tr("bool"))
		{
			Arg a(BooleanType, id.value());		 
			return addArg(a);
		}
		else if(t.value() == QObject::tr("void"))
		{
			Arg a(VoidType, id.value());
			return addArg(a);
		}
		else
			qDebug() << "ERR(Procedure setRetType() ) : Unknown type!";
		return false;

		
	}

	qint32 size() { return m_Args.size(); } 
	
	Arg arg(qint32 i) const
	{
		if(i >= m_Args.size())
			return Arg();
		else return m_Args[i];
	}

	VariableType type(qint32 i) const { return arg(i).type(); }
	QString id(qint32 i){ return arg(i).id(); }

	bool operator==(const Procedure &p)
	{
		if(m_Id == p.m_Id && m_Args.size() == p.m_Args.size() )
		{
			for(int i = 0; i < m_Args.size(); ++i)
			{
				if( type(i) != p.type(i) )
					return false;
			}
			return true;
		}
		return false;
	}

	bool operator<(const Procedure &p) const
	{	
		if(m_Args.size() != p.m_Args.size() && m_Id == p.m_Id)
			return m_Args.size() < p.m_Args.size();
		if(m_Args.size() == p.m_Args.size() && m_Id == p.m_Id)
		{		
			for(int i = 0; i < m_Args.size(); ++i)
			{
				if( type(i) < p.type(i) )
					return true;
			}
			return false;
		}
		return m_Id.toAscii() < p.m_Id.toAscii();			
	}
};

#endif // PROCEDURE_H